use std::{future::IntoFuture, ops::Index};

use bytes::Bytes;
// use crate::{minio_client::MinioClientState, models::*};
use anyhow::{anyhow, Error, Result};
use axum::{
    extract::{Extension, Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    routing::{delete, get, post, patch},
    Router,
};
// use crate::http_helper::*;
use crate::{
    models,
    utils::{self, http_helper::*},
};
use axum_macros::debug_handler;
use base64::prelude::*;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use serde_json::json;
use tracing::{debug, error};
use uuid::Uuid;

// use sqlx::PgPool;
// use tracing::debug;
use crate::app_error::*;
use crate::models::auth::*;
use crate::models::metainfo::*;
use crate::AppState;
use reqwest::{self, Url};
use std::sync::Arc;
use tower_http::trace::TraceLayer;

pub fn routes(state: Arc<AppState>) -> Router {
    Router::new()
        .route("/", post(create_user))
        .route("/by-username/{username}", get(get_user_by_username))
        .route("/{id}", get(get_user_by_id))
        .route("/", get(get_all_users))
        .route("/{id}/password", patch(update_user_password))
        .route("/{id}/role", patch(update_user_role))
        // .route("/{id}", delete(delete_user))
        .layer(TraceLayer::new_for_http())
        .with_state(state)
}

async fn create_user(
    State(app_state): State<Arc<AppState>>,
    _: AdminClaims,
    AppJson(payload): AppJson<models::CreateUserRequest>,
) -> Result<impl IntoResponse, AppError> {
    let password_hash = utils::hash_password(&payload.password)?;
    let role = models::Role::from_str(payload.role.as_str()).ok_or(anyhow!("Invalid role"))?;

    app_state
        .pg_dao
        .users_dao
        .create_user(&payload.username, &password_hash, role)
        .await?;

    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: "",
    }))
}

pub async fn get_user_by_username(
    State(app_state): State<Arc<AppState>>,
    _: AdminClaims,
    Path(username): Path<String>,
) -> Result<impl IntoResponse, AppError> {
    let user = app_state
        .pg_dao
        .users_dao
        .get_user_by_username(&username)
        .await?;

    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: json!({
            "user": user,
        }),
    }))
}

pub async fn get_user_by_id(
    State(app_state): State<Arc<AppState>>,
    _: AdminClaims,
    Path(id): Path<i64>,
) -> Result<impl IntoResponse, AppError> {
    let user = app_state
        .pg_dao
        .users_dao
        .get_user_by_id(id)
        .await?;

    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: json!({
            "user": user,
        }),
    }))
}

pub async fn get_all_users(
    State(app_state): State<Arc<AppState>>,
    _: AdminClaims,
) -> Result<impl IntoResponse, AppError> {
    let users = app_state.pg_dao.users_dao.get_all_users().await?;

    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: json!({
            "users": users,
        }),
    }))
}

async fn update_user_password(
    State(app_state): State<Arc<AppState>>,
    _: AdminClaims,
    Path(id): Path<i64>,
    AppJson(payload): AppJson<models::UpdateUserPasswordRequest>,
) -> Result<impl IntoResponse, AppError> {
    app_state
        .pg_dao
        .users_dao
        .update_user_password(id, payload.new_password.as_str())
        .await?;

    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: "",
    }))
}

async fn update_user_role(
    State(app_state): State<Arc<AppState>>,
    _: AdminClaims,
    Path(id): Path<i64>,
    AppJson(payload): AppJson<models::UpdateUserRoleRequest>,
) -> Result<impl IntoResponse, AppError> {
    let role = models::Role::from_str(payload.new_role.as_str()).ok_or(anyhow!("Invalid role"))?;

    app_state
        .pg_dao
        .users_dao
        .update_user_role(id, role)
        .await?;

    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: "",
    }))
}

async fn delete_user(
    State(app_state): State<Arc<AppState>>,
    _: AdminClaims,
    Path(id): Path<i64>,
) -> Result<impl IntoResponse, AppError> {
    app_state
        .pg_dao
        .users_dao
        .delete_user(id)
        .await?;
    
    // 还需要删除该用户的favorites，playlists
    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: "",
    }))
}
